Popular Searches
Popular Course Categories
Popular Courses

Exploring the Throwable, Error, and Exception Hierarchy

Exploring the Throwable, Error, and Exception Hierarchy

Exception Handling and Debugging

Exploring the Throwable, Error, and Exception Hierarchy in Java

Course: Core Java Training

Topic: Exploring the Throwable, Error, and Exception Hierarchy in Java

Course Link: Core Java Training Course

Demo Link: Register for a Free Course Demo

JustAcademy Website: Visit JustAcademy


1. Introduction to the Java Throwable Hierarchy

Java provides a structured mechanism for representing and handling abnormal situations that occur during program execution. This mechanism is based on the Throwable class and its subclasses, primarily Error and Exception.

When a problem occurs, Java can create or throw an object that describes the problem. This object may contain a message, a cause, and information about where the problem occurred. A program can catch certain throwable objects and respond appropriately.

Understanding the throwable hierarchy helps developers distinguish between serious system-level problems, recoverable application problems, and programming mistakes.

2. Learning Objectives

  • Understand the purpose of the Throwable class.
  • Explore the relationship between Throwable, Error, and Exception.
  • Differentiate between checked and unchecked exceptions.
  • Understand common subclasses such as IOException, NullPointerException, and OutOfMemoryError.
  • Learn how to throw, catch, and propagate exceptions.
  • Create custom exception classes in Java.
  • Apply best practices for handling errors and exceptions.

3. What Is Throwable in Java?

Throwable is the root class of Java's throwable hierarchy. Only instances of Throwable or its subclasses can be thrown using the throw statement and caught by a catch block.

It provides common methods for describing and examining a problem, including its message, cause, and stack trace.

Important Methods of Throwable

Method Description
getMessage() Returns the detail message associated with the throwable, if available.
getCause() Returns the underlying cause, if one has been set.
toString() Returns a string representation of the throwable.
printStackTrace() Prints the throwable and its stack trace, typically to the standard error stream.
getStackTrace() Returns an array describing the stack trace elements.
initCause(Throwable cause) Sets the cause when it has not already been initialized.
getSuppressed() Returns exceptions suppressed during certain resource-handling operations.

Example: Using Throwable Methods

public class ThrowableExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;
            System.out.println(result);
        } catch (ArithmeticException e) {
            System.out.println("Message: " + e.getMessage());
            System.out.println("Type: " + e);
            e.printStackTrace();
        }
    }
}

Explanation: Dividing an integer by zero causes an ArithmeticException. The catch block receives the exception object and uses its methods to display information about the problem.

4. Understanding the Java Throwable Hierarchy

The main hierarchy can be represented as follows:

Object
  |
  +-- Throwable
        |
        +-- Error
        |     |
        |     +-- OutOfMemoryError
        |     +-- StackOverflowError
        |     +-- AssertionError
        |
        +-- Exception
              |
              +-- IOException
              |     +-- FileNotFoundException
              |
              +-- SQLException
              |
              +-- RuntimeException
                    +-- ArithmeticException
                    +-- NullPointerException
                    +-- ArrayIndexOutOfBoundsException
                    +-- IllegalArgumentException

This is a simplified view of the hierarchy. Java contains many additional subclasses. Some classes, such as FileNotFoundException, extend other exception classes rather than directly extending Exception.

Main Categories

Category Purpose Typical Handling
Throwable Root type for objects that can be thrown and caught. Usually handled through its more specific subclasses.
Error Represents serious problems associated with the JVM or execution environment. Usually not handled as an ordinary application problem.
Exception Represents conditions an application may need to handle. Handled or declared according to the exception type.
RuntimeException Represents unchecked exceptions, often related to programming mistakes or invalid operations. Prevented through validation and corrected in code; selectively caught when appropriate.

5. What Is an Error in Java?

An Error is a subclass of Throwable that represents serious problems commonly associated with the Java Virtual Machine, resource exhaustion, or other conditions from which normal application recovery may be difficult.

Errors are unchecked, so Java does not require a method to catch or declare them. Developers generally focus on preventing their causes, preserving useful diagnostic information, and ensuring that applications shut down or recover safely when possible.

Common Types of Errors

Error Description Example Cause
OutOfMemoryError The JVM cannot allocate the required memory. Excessive memory consumption or insufficient heap space.
StackOverflowError The thread's stack becomes exhausted. Deep or infinite recursion.
AssertionError An enabled assertion fails. A condition checked with the assert statement evaluates to false.
NoClassDefFoundError The JVM cannot find a class definition that was available when related code was compiled or loaded. A missing runtime dependency or class-loading problem.
LinkageError A class dependency or linking operation encounters an incompatibility. Conflicting or incompatible versions of classes.

Example: StackOverflowError

public class StackOverflowExample {
    static void display() {
        display(); // Recursive call without a stopping condition
    }

    public static void main(String[] args) {
        display();
    }
}

Explanation: The method repeatedly calls itself without a base condition. Eventually, the thread's stack may run out of space, resulting in a StackOverflowError.

Important: Do not intentionally run this example in a production environment. A safer approach is to use a correct base condition or an iterative solution.

6. What Is an Exception in Java?

An Exception is a subclass of Throwable that represents a condition an application may need to detect and handle. Examples include a missing file, invalid input, or a failed database operation.

Exceptions are divided into two major groups: checked exceptions and unchecked exceptions. The distinction determines whether Java requires a method to catch or declare the exception at compile time.

6.1 Checked Exceptions

Checked exceptions are exception types other than RuntimeException and its subclasses. The compiler checks that a method either handles a checked exception with a suitable catch block or declares it using throws, subject to Java's exception rules.

Examples include:

  • IOException
  • FileNotFoundException
  • SQLException
  • ClassNotFoundException
  • InterruptedException

Example: Handling a Checked Exception

import java.io.FileReader;
import java.io.IOException;

public class CheckedExceptionExample {
    public static void main(String[] args) {
        try (FileReader reader = new FileReader("data.txt")) {
            System.out.println("File opened successfully.");
        } catch (IOException e) {
            System.out.println("Unable to read the file: " + e.getMessage());
        }
    }
}

Explanation: Creating a FileReader can throw an IOException, including a FileNotFoundException. The try-with-resources statement automatically closes the reader, and the catch block handles an I/O failure.

6.2 Unchecked Exceptions

Unchecked exceptions include RuntimeException and its subclasses. The compiler does not require these exceptions to be caught or declared.

They often occur because of invalid operations, missing validation, or incorrect assumptions in the program.

Common examples include:

  • ArithmeticException
  • NullPointerException
  • ArrayIndexOutOfBoundsException
  • IllegalArgumentException
  • NumberFormatException
  • ClassCastException

Example: Unchecked Exception

public class UncheckedExceptionExample {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30};

        try {
            System.out.println(numbers[5]);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Invalid array index.");
        }
    }
}

Explanation: The array contains only three elements, with valid indexes from 0 to 2. Accessing index 5 causes an ArrayIndexOutOfBoundsException, which is an unchecked exception.

7. Difference Between Error and Exception

Basis Error Exception
Parent class Throwable Throwable
Typical meaning Serious JVM, resource, or execution problem. Condition an application may need to handle.
Recoverability Often difficult to recover from safely. May be recoverable depending on the situation.
Compiler checking Unchecked. May be checked or unchecked.
Examples OutOfMemoryError, StackOverflowError IOException, NullPointerException
Recommended approach Investigate the underlying cause and protect system stability. Handle expected failures, validate inputs, and propagate failures when appropriate.

8. Difference Between Checked and Unchecked Exceptions

Basis Checked Exception Unchecked Exception
Compiler enforcement Must be caught or declared. No catch-or-declare requirement.
Class hierarchy Subclass of Exception that is not a RuntimeException subclass. RuntimeException or one of its subclasses.
Common examples IOException, SQLException NullPointerException, IllegalArgumentException
Typical use Operations with failures that callers may reasonably handle. Programming errors, invalid arguments, or invalid object states.

9. Understanding RuntimeException

RuntimeException is a subclass of Exception. It serves as the parent class for many unchecked exceptions.

These exceptions frequently indicate that an operation cannot be performed because a value, reference, or program state is invalid.

Example: NullPointerException

public class NullPointerExample {
    public static void main(String[] args) {
        String name = null;

        try {
            System.out.println(name.length());
        } catch (NullPointerException e) {
            System.out.println("The name reference is null.");
        }
    }
}

Explanation: The variable name does not refer to a String object. Calling length() through that null reference causes a NullPointerException.

Best practice: Prefer preventing the invalid state through validation or appropriate null handling rather than relying on exceptions for normal control flow.

10. How the Throwable Hierarchy Works

When a throwable object is created and thrown, Java looks for a matching handler as the call stack unwinds. If a matching handler is found, execution continues according to that handler. If no suitable handler is found, the thread's uncaught-exception handling mechanism is invoked.

  1. A problem occurs during program execution, or code explicitly creates and throws a throwable object.
  2. Java creates or uses an object belonging to Throwable or one of its subclasses.
  3. The current method is checked for a matching catch block.
  4. If no handler matches, the throwable propagates to the calling method.
  5. This process continues until a handler is found or the throwable remains uncaught.
  6. An uncaught throwable is passed to the thread's uncaught-exception handler, typically resulting in a stack trace being reported.

Example: Exception Propagation

public class ExceptionPropagationExample {
    static void methodA() {
        int result = 10 / 0;
    }

    static void methodB() {
        methodA();
    }

    public static void main(String[] args) {
        try {
            methodB();
        } catch (ArithmeticException e) {
            System.out.println("Exception handled in main.");
        }
    }
}

Explanation: The exception originates in methodA(). Since neither methodA() nor methodB() catches it, it propagates to main(), where the matching catch block handles it.

11. Using throw and throws

11.1 The throw Keyword

The throw keyword explicitly throws a single throwable object from a method or block.

public class ThrowExample {
    static void checkAge(int age) {
        if (age < 18) {
            throw new IllegalArgumentException(
                "Age must be at least 18."
            );
        }

        System.out.println("Access granted.");
    }

    public static void main(String[] args) {
        try {
            checkAge(16);
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
        }
    }
}

11.2 The throws Keyword

The throws keyword appears in a method declaration to identify throwable types that the method may propagate to its caller. It is commonly used with checked exceptions.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class ThrowsExample {
    static String readFile(Path path) throws IOException {
        return Files.readString(path);
    }

    public static void main(String[] args) {
        try {
            System.out.println(readFile(Path.of("data.txt")));
        } catch (IOException e) {
            System.out.println("File operation failed.");
        }
    }
}

Difference Between throw and throws

Feature throw throws
Purpose Throws a specific throwable object. Declares throwable types a method may propagate.
Location Inside a method or block. In a method or constructor declaration.
Number Throws one object at a time. Can declare multiple throwable types separated by commas.
Example throw new IOException(); void read() throws IOException

12. Creating Custom Exceptions

Java allows developers to create their own exception classes when built-in exception types do not clearly describe a business rule or application-specific failure.

  • Extend Exception to create a checked custom exception.
  • Extend RuntimeException to create an unchecked custom exception.
  • Use descriptive class names and messages.
  • Preserve the original cause when wrapping a lower-level failure.

Example: Custom Checked Exception

class InsufficientBalanceException extends Exception {
    public InsufficientBalanceException(String message) {
        super(message);
    }
}

public class BankAccount {
    private double balance = 1000.0;

    public void withdraw(double amount)
            throws InsufficientBalanceException {
        if (amount <= 0) {
            throw new IllegalArgumentException(
                "Withdrawal amount must be positive."
            );
        }

        if (amount > balance) {
            throw new InsufficientBalanceException(
                "Insufficient balance for withdrawal."
            );
        }

        balance -= amount;
        System.out.println("Remaining balance: " + balance);
    }

    public static void main(String[] args) {
        BankAccount account = new BankAccount();

        try {
            account.withdraw(1500.0);
        } catch (InsufficientBalanceException e) {
            System.out.println(e.getMessage());
        }
    }
}

Explanation: The InsufficientBalanceException class represents a specific banking rule violation. Because it extends Exception directly, it is checked and must be caught or declared by calling code.

13. Exception Chaining and Causes

Exception chaining allows an application to wrap a lower-level exception inside a higher-level exception while preserving the original cause. It is useful when translating technical failures into errors meaningful to another layer of the application.

class DataAccessException extends Exception {
    public DataAccessException(String message, Throwable cause) {
        super(message, cause);
    }
}

public class ExceptionChainingExample {
    static void loadData() throws DataAccessException {
        try {
            Integer.parseInt("abc");
        } catch (NumberFormatException e) {
            throw new DataAccessException(
                "Unable to load valid data.", e
            );
        }
    }

    public static void main(String[] args) {
        try {
            loadData();
        } catch (DataAccessException e) {
            System.out.println(e.getMessage());
            System.out.println("Original cause: " + e.getCause());
        }
    }
}

Explanation: The higher-level exception communicates the operation that failed, while getCause() retains the original NumberFormatException for debugging. In a real application, use this pattern when it provides useful context, and avoid wrapping exceptions unnecessarily.

14. Best Practices for Error and Exception Handling

  • Catch specific exceptions: Prefer IOException or another expected type over a broad catch when possible.
  • Do not swallow exceptions: Empty catch blocks can hide failures and make debugging difficult.
  • Provide useful messages: Explain the failed operation without exposing passwords, tokens, or sensitive information.
  • Use try-with-resources: Automatically close resources such as readers, streams, and database resources that implement AutoCloseable.
  • Preserve causes: When translating an exception, retain the original cause where useful.
  • Avoid using exceptions for ordinary control flow: Validate expected conditions directly.
  • Do not catch Throwable casually: It includes both exceptions and serious errors. Broad catching can interfere with failures that should not be treated as ordinary application problems.
  • Do not assume every Error is unrecoverable: Some errors may be observed or handled in specialized systems, but ordinary application code should not depend on recovering from them.
  • Log appropriately: Record enough diagnostic context while avoiding duplicate logs and sensitive data.
  • Restore interruption when appropriate: If catching InterruptedException and not propagating it, commonly restore the interrupt status with Thread.currentThread().interrupt().

15. Common Mistakes to Avoid

Mistake Why It Is a Problem Better Approach
Catching Exception for every situation May hide the specific cause and handle unrelated failures incorrectly. Catch the types that the current code can reasonably handle.
Ignoring a caught exception The application may continue in an invalid state without warning. Recover, report, or propagate the exception deliberately.
Using throw with a message string The keyword requires a throwable object, not a plain string. Use throw new IllegalArgumentException("Invalid value");.
Assuming all exceptions are checked RuntimeException subclasses are unchecked. Learn the distinction between checked and unchecked types.
Catching Error to continue normal execution The program may be unable to operate safely. Investigate the underlying cause and design for safe failure.
Replacing an exception without its cause Important diagnostic details may be lost. Use a constructor that accepts the original cause.

16. Practical Exercise

Exercise 1: Identify the hierarchy.

Classify the following types as an Error, checked exception, or unchecked exception:

  • OutOfMemoryError
  • IOException
  • NullPointerException
  • StackOverflowError
  • SQLException
  • IllegalArgumentException

Exercise 2: Handle invalid input.

Write a Java program that converts a string to an integer. Catch NumberFormatException and display a useful message if the input is not numeric.

Exercise 3: Build a custom exception.

Create an InvalidMarksException class and use it to reject marks outside the range of 0 to 100.

Exercise 4: Explore exception propagation.

Create three methods where the deepest method throws an exception and the outermost method handles it. Observe how the stack trace shows the method calls.

17. Mini Project: Student Marks Validation

Build a small program that accepts student marks, validates the input, and reports invalid values using an appropriate exception.

class InvalidMarksException extends Exception {
    public InvalidMarksException(String message) {
        super(message);
    }
}

public class StudentMarks {
    static void validateMarks(int marks)
            throws InvalidMarksException {
        if (marks < 0 || marks > 100) {
            throw new InvalidMarksException(
                "Marks must be between 0 and 100."
            );
        }

        System.out.println("Valid marks: " + marks);
    }

    public static void main(String[] args) {
        try {
            validateMarks(85);
            validateMarks(120);
        } catch (InvalidMarksException e) {
            System.out.println("Validation failed: " + e.getMessage());
        }
    }
}

Expected behavior: The first value is accepted. The second value causes the custom checked exception, which is handled by the catch block.

18. Interview Questions and Answers

Q1. What is Throwable in Java?

Answer: Throwable is the root class for objects that can be thrown and caught in Java. Its two principal direct subclasses are Error and Exception.

Q2. What is the difference between Error and Exception?

Answer: An Error generally represents a serious JVM or execution problem, while an Exception represents a condition that application code may need to handle. Both are unchecked or checked according to their position in the hierarchy and compiler rules, with Errors being unchecked.

Q3. Are all exceptions checked exceptions?

Answer: No. Exceptions that extend RuntimeException are unchecked. Other exception subclasses are generally checked unless they belong to the unchecked hierarchy.

Q4. Is NullPointerException checked or unchecked?

Answer: It is unchecked because it extends RuntimeException.

Q5. Can we throw an Error manually?

Answer: Yes. Java permits code to throw an instance of Error or its subclass, but application code should not normally use Errors to represent routine business failures.

Q6. Can a catch block catch Throwable?

Answer: Yes, because Throwable is the common superclass of errors and exceptions. However, catching it broadly is usually inappropriate for normal application handling.

Q7. What is exception propagation?

Answer: Exception propagation occurs when a method does not handle a thrown exception and it travels up the call stack until a matching handler is found or the exception remains uncaught.

Q8. Why are custom exceptions useful?

Answer: They represent application-specific failures clearly, improve readability, and allow callers to handle particular business conditions explicitly.

Q9. What is exception chaining?

Answer: Exception chaining preserves an underlying cause inside a higher-level exception, allowing code to provide context without losing the original diagnostic information.

Q10. What happens if an exception is not caught?

Answer: It propagates until no matching handler is found. The thread's uncaught-exception handler is then invoked, and the thread generally terminates.

19. Quick Revision Checklist

  • Throwable is the root of the throwable hierarchy.
  • Error represents serious execution or environment problems and is unchecked.
  • Exception represents conditions that applications may need to handle.
  • Checked exceptions must be caught or declared.
  • RuntimeException and its subclasses are unchecked.
  • throw throws an object; throws declares throwable types in a method signature.
  • Exception propagation moves up the call stack when no local handler matches.
  • Custom exceptions can represent business-specific failures.
  • Exception chaining preserves the underlying cause.
  • Catch specific exception types and avoid silently ignoring failures.

20. Conclusion

The Java throwable hierarchy provides a consistent way to represent failures and abnormal conditions. Understanding the roles of Throwable, Error, and Exception helps developers make informed decisions about validation, exception handling, and application recovery.

By distinguishing checked exceptions from unchecked exceptions, using custom exceptions where appropriate, preserving causes, and following sound error-handling practices, developers can create Java applications that are easier to maintain, diagnose, and operate reliably.

To learn more about Java fundamentals and exception handling, explore the Core Java Training Course, register for a course demo, or visit the JustAcademy website.

Previous Next
whatsapp